#include <windows.h>
#include <GL/glut.h>
#include <stdlib.h>


static unsigned char buf[10];
static unsigned char prt = 0;
static unsigned char status[10];

static struct quaternion_t
{
	GLdouble x;
	GLdouble y;
	GLdouble z;
	GLdouble w;
} quaternion;

static GLdouble matrix[16];

// refer: http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
void get_matrix_from_quaternion(struct quaternion_t *q,
								GLdouble *mat)
{
	GLdouble xx, xy, xz, xw, yy, yz, yw, zz, zw;
	xx = q->x * q->x;
	xy = q->x * q->y;
	xz = q->x * q->z;
	xw = q->x * q->w;
	yy = q->y * q->y;
	yz = q->y * q->z;
	yz = q->y * q->w;
	zz = q->z * q->z;
	zw = q->z * q->w;
    mat[0]  = 1 - 2 * ( yy + zz );
    mat[1]  =     2 * ( xy - zw );
    mat[2]  =     2 * ( xz + yw );
    mat[4]  =     2 * ( xy + zw );
    mat[5]  = 1 - 2 * ( xx + zz );
    mat[6]  =     2 * ( yz - xw );
    mat[8]  =     2 * ( xz - yw );
    mat[9]  =     2 * ( yz + xw );
    mat[10] = 1 - 2 * ( xx + yy );
    mat[3]  = mat[7] = mat[11] = mat[12] = mat[13] = mat[14] = 0;
    mat[15] = 1;
}


static void resize(int width, int height)
{
    const float ar = (float) width / (float) height;

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void drawString(const char* str) //屏幕显示字体
{
	static int isFirstCall = 1;
	static GLuint lists;

	if (isFirstCall) {
		isFirstCall = 0;
		// 申请MAX_CHAR个连续的显示列表编号
		lists = glGenLists(128);
		// 把每个字符的绘制命令都装到对应的显示列表中
		wglUseFontBitmaps(wglGetCurrentDC(), 0, 128, lists);
	}
	// 调用每个字符对应的显示列表，绘制每个字符
	for (; *str != '\0'; ++str) {
		glCallList(lists + *str);
	}
}

static draw_polygon(const GLfloat *point1, const GLfloat *point2,
					const GLfloat *point3, const GLfloat *point4)
{
	glBegin(GL_POLYGON);
		glVertex3fv(point1);
		glVertex3fv(point2);
		glVertex3fv(point3);
		glVertex3fv(point4);
	glEnd();
}

#define MODEL_LENGTH	5.0
#define MODEL_WIDTH		5.0
#define MODEL_HEIGHT	1.0
const GLfloat model[8][3] =
{
	{MODEL_LENGTH, MODEL_LENGTH, MODEL_HEIGHT / 2},
	{MODEL_LENGTH, -MODEL_LENGTH, MODEL_HEIGHT / 2},
	{-MODEL_LENGTH, -MODEL_LENGTH, MODEL_HEIGHT / 2},
	{-MODEL_LENGTH, MODEL_LENGTH, MODEL_HEIGHT / 2},
	{MODEL_LENGTH, MODEL_LENGTH, -MODEL_HEIGHT / 2},
	{MODEL_LENGTH, -MODEL_LENGTH, -MODEL_HEIGHT / 2},
	{-MODEL_LENGTH, -MODEL_LENGTH, -MODEL_HEIGHT / 2},
	{-MODEL_LENGTH, MODEL_LENGTH, -MODEL_HEIGHT / 2},
};

static void display(void)
{
	unsigned char input[20];
	unsigned char output[20];

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(20.0,10.0,15.0,0.0,0.0,0.0,0.0,0.0,1.0);

	// input
	memcpy(input, "Input: " , 7);
	memcpy(&input[7], buf , prt);
	input[7 + prt + 1] = '\0';
	glRasterPos3f(0.0, -20.0, 5.0);
	drawString(input);
	// output
	memcpy(output, "Output: " , 8);
	memcpy(&output[8], status , 10);
	output[19] = '\0';
	glRasterPos3f(0.0, -21, 4.0);
	drawString(output);

	// 基本坐标系
	glColor3d(0,0,0);
	glRasterPos3f(0.0, -10.0, 10.0);
	drawString("X OFFSET: 0cm");
	glRasterPos3f(0.0, -10.25, 9.0);
	drawString("Y OFFSET: 0cm");
	glRasterPos3f(0.0, -10.5, 8.0);
	drawString("Z OFFSET: 0cm");

	glLineWidth(5.0);
    glColor3d(255,0,0);
	glBegin(GL_LINES);
	glVertex3f(0.0, 0.0, 0.0);
	glVertex3f(10.0, 0.0, 0.0);
	glEnd();
	glRasterPos3f(2.0, 0.5, 0.0);
	drawString("2");
	glRasterPos3f(4.0, 0.5, 0.0);
	drawString("4");
	glRasterPos3f(6.0, 0.5, 0.0);
	drawString("6");
	glRasterPos3f(8.0, 0.5, 0.0);
	drawString("8");
	glRasterPos3f(10.0, 0.5, 0.0);
	drawString("10");
	glRasterPos3f(11.0, 0.0, 0.0);
	drawString("X");
    glColor3d(0,255,0);
	glBegin(GL_LINES);
	glVertex3f(0.0, 0.0, 0.0) ;
	glVertex3f(0.0, 10.0, 0.0) ;
	glEnd();
	glRasterPos3f(0.0, 2.0, 0.5);
	drawString("2");
	glRasterPos3f(0.0, 4.0, 0.5);
	drawString("4");
	glRasterPos3f(0.0, 6.0, 0.5);
	drawString("6");
	glRasterPos3f(0.0, 8.0, 0.5);
	drawString("8");
	glRasterPos3f(0.0, 10.0, 0.5);
	drawString("10");
	glRasterPos3f(0.0, 11.0, 0.0);
	drawString("Y");
    glColor3d(0,0,255);
	glBegin(GL_LINES);
	glVertex3f(0.0, 0.0, 0.0) ;
	glVertex3f(0.0, 0.0, 10.0) ;
	glEnd();
	glRasterPos3f(0.5, -0.5, 2.0);
	drawString("2");
	glRasterPos3f(0.5, -0.5, 4.0);
	drawString("4");
	glRasterPos3f(0.5, -0.5, 6.0);
	drawString("6");
	glRasterPos3f(0.5, -0.5, 8.0);
	drawString("8");
	glRasterPos3f(0.5, -0.5, 10.0);
	drawString("10");
	glRasterPos3f(0.0, 11.0, 0.0);
	glRasterPos3f(0.0, 0.0, 11.0);
	drawString("Z");

	// 随动模型
	glPushMatrix();
	glMultMatrixd(matrix);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(1.0f,0.0f,0.0f,0.1f);
	draw_polygon(model[0], model[1], model[2], model[3]);
	draw_polygon(model[4], model[5], model[6], model[7]);
	glColor4f(1.0f,1.0f,1.0f,0.9f);
	draw_polygon(model[0], model[3], model[4], model[7]);
	draw_polygon(model[1], model[2], model[4], model[5]);
	glColor4f(1.0f,1.0f,1.0f,0.9f);
	draw_polygon(model[0], model[1], model[4], model[5]);
	draw_polygon(model[2], model[3], model[6], model[7]);

	glDisable(GL_BLEND);
	glPopMatrix();

    glutSwapBuffers();
}

LPCTSTR lpComx;
HANDLE hCom;
static int comm_input(unsigned char comxID)
{
	static int connected = 0;

	if (connected)
		return -1;

	switch(comxID)
	{
	case 1:
		lpComx="COM1";
		break;
	case 2:
		lpComx="COM2";
		break;
	case 3:
		lpComx="COM3";
		break;
	case 4:
		lpComx="COM4";
		break;
	case 5:
		lpComx="COM5";
		break;
	case 6:
		lpComx="COM6";
		break;
	case 7:
		lpComx="COM7";
		break;
	case 8:
		lpComx="COM8";
		break;
	case 9:
		lpComx="COM9";
		break;
	default:
		return -1;
		break;
	}

	hCom=CreateFile(lpComx,
					GENERIC_READ|GENERIC_WRITE,
					0,
					NULL,
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
					NULL);
	if (hCom == INVALID_HANDLE_VALUE)
	{
		return -1;
	}

	//配置串口
	SetupComm(hCom,1024,1024); //输入缓冲区和输出缓冲区的大小都是1024
	COMMTIMEOUTS TimeOuts;
	//设定读超时
	TimeOuts.ReadIntervalTimeout = 1000;
	TimeOuts.ReadTotalTimeoutMultiplier = 0;
	TimeOuts.ReadTotalTimeoutConstant = 0;
	//设定写超时
	TimeOuts.WriteTotalTimeoutMultiplier = 500;
	TimeOuts.WriteTotalTimeoutConstant = 2000;
	SetCommTimeouts(hCom, &TimeOuts); //设置超时

	DCB dcb;
	GetCommState(hCom, &dcb);
	dcb.BaudRate =921600;
	dcb.ByteSize = 8;
	dcb.Parity=NOPARITY;
	dcb.Parity=ONESTOPBIT;
	SetCommState(hCom, &dcb);

	PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

	connected = 1;
	return 0;
}

static void key(unsigned char key, int x, int y)
{
	if ((key == 0x20) || (key == '\r'))
	{
		if (prt == 1)
		{
			unsigned char i;
			if ((buf[0] >= 0x31) && (buf[0] <= 0x39))
			{
				i = (buf[0] - 0x30);
				if (comm_input(i) < 0)
					memcpy(status, "Fail", 5);
				else
					memcpy(status, "Done", 5);
			}
		}
		else if (prt == 2)
		{
			unsigned char i;
			if ((buf[0] >= 0x31) && (buf[0] <= 0x39))
			{
				if ((buf[1] >= 0x30) && (buf[1] <= 0x39))
				{
					i = (buf[0] - 0x30) * 10 + (buf[1] - 0x30);
					if (comm_input(i) < 0)
						memcpy(status, "Fail", 5);
					else
						memcpy(status, "Done", 5);
				}
			}
		}
		else
		{
			if (memcmp(buf, "exit", 4) == 0)
			{
				exit(0);
			}
		}
		prt = 0;
	}
	else if (prt < 10)
	{
		buf[prt++] = key;
	}

    glutPostRedisplay();
}

static void idle(void)
{
    glutPostRedisplay();
}

const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 1.0f, 0.0f, 0.0f, 0.0f };

const GLfloat mat_ambient[]    = { 0.5f, 0.5f, 0.5f, 1.0f };
const GLfloat mat_diffuse[]    = { 0.5f, 0.5f, 0.5f, 1.0f };
const GLfloat mat_specular[]   = { 0.5f, 0.5f, 0.5f, 1.0f };
const GLfloat high_shininess[] = { 10.0f };


int main(int argc, char *argv[])
{
    matrix[0] = matrix[5] =  matrix[10] = matrix[15] = 1.0;
    matrix[1] = matrix[2] = matrix[3] = matrix[4] = 0.0;
    matrix[6] = matrix[7] = matrix[8] = matrix[9] = 0.0;
	matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0.0;

    glutInit(&argc, argv);
    glutInitWindowSize(720,480);
    glutInitWindowPosition(300,120);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("UAV Displayer");

    glutReshapeFunc(resize);	//调整窗体大小调用resize进行重绘
    glutKeyboardFunc(key);		//按键回调函数
    glutIdleFunc(idle);			//空闲时间 一般会用于刷新实现动画效果
    glutDisplayFunc(display);	//显示

    glClearColor(1,1,1,1);

    //深度缓存，3d效果必备
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    //使能光源0
    glEnable(GL_LIGHT0);
    glEnable(GL_NORMALIZE);
    //灯光可以给物体上色
    glEnable(GL_COLOR_MATERIAL);
    //使用灯光
    glEnable(GL_LIGHTING);

    //GL_AMBIENT    环境光
    //GL_DIFFUSE    漫反射
    //GL_SPECULAR   镜面反射强度
    //GL_SHININESS   镜面指数
    //GL_POSITION   光源位置
    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);

    glutMainLoop();

    return EXIT_SUCCESS;
}
